package com.xc.file.config.aspect;

import com.xc.tool.utils.IpUtils;
import com.xc.tool.utils.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Stream;

/**
 * <p>项目名称: Stars</p>
 * <p>描述: 业务日志记录类</p>
 * <P>创建人: 小程</p>
 * <P>创建人邮箱: 779943476@qq.com</p>
 * <p>创建时间: 2019/7/2</p>
 *
 * @version v1.0
 */
@Aspect
@Component
@Slf4j
@Order(4)
public class LogAspect extends AbstractPoint {


    /**
     * <p>功能描述: 请求日志记录 </p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param joinPoint 切面数据信息
     */
    @Before("writeLog()")
    public void logRequest(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        String method = request.getMethod();
        request.setAttribute("requestTime", new Date().getTime());
        String params = "";
        if ("POST".equals(method) || "PUT".equals(method)) {
            Object[] paramsArray = joinPoint.getArgs();
            params = Optional.ofNullable(paramsArray).map(arrays -> {
                StringBuilder stringBuilder = new StringBuilder();
                Stream.of(arrays).forEach(o -> {
                    if (!(o instanceof MultipartFile) && !(o instanceof HttpServletRequest)) {
                        if (o instanceof List) {
                            stringBuilder.append(JSONUtils.getStringByList(o)).append(" ");
                        } else if (o instanceof String) {
                            stringBuilder.append(o).append(" ");
                        } else if (o instanceof String[]) {
                            stringBuilder.append(JSONUtils.getStringByList(o)).append(" ");
                        } else {
                            stringBuilder.append(JSONUtils.getStringByObject(o)).append(" ");
                        }
                    }
                });
                return stringBuilder.toString().trim();
            }).orElse("param is empty");
        } else {
            Map<String, String> map = new HashMap<>();
            for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
                map.put(entry.getKey(), entry.getValue()[0]);
            }
            Map<String, String> paramsMap = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            map.putAll(paramsMap);
            params = map.toString();
        }
        String url = request.getRequestURI();
        String clientIp = IpUtils.getClientIp(request);
        log.info("type=请求，url={},method={},ip={},param={}", url, method, clientIp, params);
    }

    /**
     * <p>功能描述: 响应日志记录 </p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param joinPoint 切面数据信息
     * @param result    返回数据对象
     */
    @AfterReturning(returning = "result", pointcut = "writeLog()")
    public void logResponse(JoinPoint joinPoint, Object result) {
        if (result != null) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String method = request.getMethod();
                Long requestTime = (Long) request.getAttribute("requestTime");
                BigDecimal responseTime = new BigDecimal(new Date().getTime() - requestTime).divide(BigDecimal.valueOf(1000), 3, RoundingMode.HALF_UP);
                String param = "";
                if (result instanceof List) {
                    param = JSONUtils.getStringByList(result);
                } else if (result instanceof String) {
                    param = (String) result;
                } else {
                    param = JSONUtils.getStringByObject(result);
                }
                log.info("type=响应，url={},method={},ip={},requestTime={},result={}",
                        request.getRequestURI(),
                        method,
                        IpUtils.getClientIp(request),
                        responseTime,
                        param);
            }
        }
    }
}
